package com.wxy.demo.tencent_cos;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.ImmutableMap;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.exception.MultiObjectDeleteException;
import com.qcloud.cos.exception.MultiObjectDeleteException.DeleteError;
import com.qcloud.cos.model.*;
import com.qcloud.cos.model.DeleteObjectsRequest.KeyVersion;
import com.qcloud.cos.model.DeleteObjectsResult.DeletedObject;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.Download;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import com.wxy.demo.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * @description: 腾讯云COS云存储工具类-不带认证
 */
@Slf4j
public class TencentCosStoreUtils {

    /**
     * 域名
     */
    private static final String domain = "https://tce-autotest-1304962210.cos.ap-chongqing.myqcloud.com/";

    /**
     * secretId 秘钥id
     */
    private static final String secretId = "AKIDEGFE1gBUZO0NVP4FJ8pJYw71mMhlHYZK";

    /**
     * SecretKey 秘钥
     */
    private static final String secretKey = "d2C8oJicO4YprsxvkN2SdfYDcmiPuCE1";

    /**
     * 地区
     */
    private static final String region = "ap-chongqing";

    /**
     * 桶
     */
    private static final String bucketName = "tce-autotest-1304962210";

    /**
     * 前缀
     */
    private static final String prefix = "tce-autotest/";

    private static final COSClient cosClient = new COSClient(new BasicCOSCredentials(secretId, secretKey),
            new ClientConfig(new Region(region)));
    ;

    /**
     * 高级上传方式，支持线程池
     *
     * @param file    文件对象
     * @param shortPath 短路径
     */
    public static String uploadFile(MultipartFile file, String shortPath) {
        // 传入一个 threadpool, 若不传入线程池, 默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient);
        Path localFile = null;
        try {
            String fileName = file.getOriginalFilename();
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            // 上传的文件临时存到本地
            localFile = Files.createTempFile(String.valueOf(System.currentTimeMillis()), suffix);
            file.transferTo(localFile);
            // 指定要上传到 COS 上对象键
            String path = UUID.randomUUID().toString();
            if (StrUtil.isNotBlank(shortPath)) {
                path = shortPath;
            }
            String key = prefix + path + suffix;

            // 分装与上传
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key,
                    localFile.toFile());
            Upload upload = transferManager.upload(putObjectRequest);
            // 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
            UploadResult uploadResult = upload.waitForUploadResult();

            return domain + key;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：上传文件失败");
        } finally {
            if (null != localFile) {
                localFile.toFile().delete();
            }
        }
    }

    /**
     * 获取文件下载URL
     */
    public static String getDownLoadUrl(String key) {
        // 设置URL过期时间为1小时 60*60*1000
        Date expiration = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
        try {
            GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(
                    bucketName, key);
            // 设置签名过期时间(可选), 若未进行设置, 则默认使用 ClientConfig 中的签名过期时间(5分钟)
            generatePresignedUrlRequest.setExpiration(expiration);
            String url = cosClient.generatePresignedUrl(generatePresignedUrlRequest).toString();
            log.info("获取文件下载URL：{}", url);
            return url;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：获取文件下载URL失败");
        }
    }

    /**
     * 下载文件到本地
     *
     * @param key       文件键
     * @param localFile 本地目录
     */
    public static Download download(String key, File localFile) {
        TransferManager transferManager = new TransferManager(cosClient);
        try {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
            // 限流使用的单位是bit/s, 这里设置下载带宽限制为 10MB/s
            getObjectRequest.setTrafficLimit(80 * 1024 * 1024);
            // 下载文件
            Download download = transferManager.download(getObjectRequest, localFile);
            // 等待传输结束（如果想同步的等待上传结束，则调用 waitForCompletion）
            download.waitForCompletion();
            return download;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：下载文件到本地失败");
        }
    }

    /**
     * 获取文件元数据信息
     *
     * @param key 文件键
     */
    public static ObjectMetadata getObjectMetadata(String key) {
        try {
            ObjectMetadata objectMetadata = cosClient.getObjectMetadata(bucketName, key);
            return objectMetadata;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：获取文件元信息失败");
        }
    }

    /**
     * 删除单个文件
     *
     * @param key 文件键
     */
    public static void deleteObject(String key) {
        try {
            cosClient.deleteObject(bucketName, key);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：删除单个文件失败");
        }
    }

    /**
     * 批量删除文件
     *
     * @param keys 文件键list
     */
    public static Map<String, Object> deleteObjects(List<String> keys) {
        DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName);
        // 设置要删除的key列表, 最多一次删除1000个
        List<KeyVersion> keyList = new ArrayList<KeyVersion>(keys.size());
        // 传入要删除的文件名
        keys.forEach(key -> {
            keyList.add(new KeyVersion(key));
        });
        deleteObjectsRequest.setKeys(keyList);
        // 批量删除文件
        try {
            DeleteObjectsResult deleteObjectsResult = cosClient.deleteObjects(deleteObjectsRequest);
            List<DeletedObject> deleteObjectResultArray = deleteObjectsResult.getDeletedObjects();
            return ImmutableMap.of("success", deleteObjectResultArray);
        } catch (MultiObjectDeleteException mde) {
            // 如果部分删除成功部分失败, 返回MultiObjectDeleteException
            List<DeletedObject> deleteObjects = mde.getDeletedObjects();
            List<DeleteError> deleteErrors = mde.getErrors();
            return ImmutableMap.of("success", deleteObjects, "error", deleteErrors);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：批量删除文件失败");
        }
    }

    /**
     * 设置指定存储桶的跨域名访问
     *
     * @param bucketName 桶
     * @param domainList 域名
     */
    public static void setBucketCrossOrigin(String bucketName, List<String> domainList) {
        try {
            BucketCrossOriginConfiguration bucketCORS = new BucketCrossOriginConfiguration();
            List<CORSRule> corsRules = new ArrayList<CORSRule>();
            CORSRule corsRule = new CORSRule();
            // 规则名称
            corsRule.setId("set-bucket-cors-test");
            // 允许的 HTTP 方法
            corsRule.setAllowedMethods(CORSRule.AllowedMethods.PUT, CORSRule.AllowedMethods.GET,
                    CORSRule.AllowedMethods.HEAD);
            corsRule.setAllowedHeaders("x-cos-grant-full-control");
            corsRule.setAllowedOrigins(domainList);
            corsRule.setExposedHeaders("x-cos-request-id");
            corsRule.setMaxAgeSeconds(60);
            corsRules.add(corsRule);
            bucketCORS.setRules(corsRules);
            cosClient.setBucketCrossOriginConfiguration(bucketName, bucketCORS);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：设置指定存储桶的跨域名访问配置信息失败");
        }
    }

    /**
     * 查询指定存储桶的跨域名访问配置信息
     *
     * @param bucketName 桶
     */
    public static List<CORSRule> getBucketCrossOrigin(String bucketName) {
        try {
            BucketCrossOriginConfiguration corsGet = cosClient
                    .getBucketCrossOriginConfiguration(bucketName);
            List<CORSRule> corsRules = corsGet.getRules();
            return corsRules;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：查询指定存储桶的跨域名访问配置信息失败");
        }
    }

    /**
     * 删除指定存储桶的跨域名访问配置
     *
     * @param bucketName 桶
     */
    public static void deleteBucketCrossOrigin(String bucketName) {
        try {
            cosClient.deleteBucketCrossOriginConfiguration(bucketName);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("COS：删除指定存储桶的跨域名访问配置失败");
        }
    }

    public static void main(String[] args) {
        String uploadFile = uploadFile(FileUtils.getMultipartFile(new File("doc/a.txt")), null);
        System.out.println(uploadFile);
    }
}
